package com.zmn.oms.third.gomegj.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.ltsopensource.core.domain.Job;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zmn.base.common.data.common.dro.area.AreaDRO;
import com.zmn.base.common.data.dubbo.interfaces.area.AreaListRemoteService;
import com.zmn.base.product.common.dto.product.ec.ProductBaseDRO;
import com.zmn.base.product.dubbo.interfaces.channel.product.third.ChannelProductThirdListRemoteService;
import com.zmn.consts.GlobalConsts;
import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.amount.AmountUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.math.MoneyUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.manager.lts.interfaces.task.TaskManager;
import com.zmn.manager.redis.RedisManager;
import com.zmn.oms.business.interfaces.messageV1.app.MessageSendAppService;
import com.zmn.oms.business.interfaces.track.OrderTrackBService;
import com.zmn.oms.common.constant.MessageRuleIdConsts;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.OrderLogConsts;
import com.zmn.oms.common.constant.RedisKeyConsts;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.manager.utils.TaskConsts;
import com.zmn.oms.model.bo.order.OrderBO;
import com.zmn.oms.model.dto.baidumap.LngLatLocation;
import com.zmn.oms.model.dto.order.proxy.*;
import com.zmn.oms.model.dto.product.OrderProductDTO;
import com.zmn.oms.model.dto.track.OrderTrackDTO;
import com.zmn.oms.model.dto.track.OrderTrackDetailDTO;
import com.zmn.oms.model.entity.remark.OrderRemark;
import com.zmn.oms.model.entity.remark.OrderRemarkDetail;
import com.zmn.oms.model.entity.serviceitem.OrderServiceItem;
import com.zmn.oms.model.entity.track.OrderTrackQuery;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.entity.work.OrderWorkLogChange;
import com.zmn.oms.model.vo.track.OrderTrackVO;
import com.zmn.oms.model.vo.work.ZsOrderWorkVO;
import com.zmn.oms.model.vo.work.modify.amount.ZsServiceItemVO;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.remark.OrderRemarkDetailService;
import com.zmn.oms.services.interfaces.remark.OrderRemarkService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.third.base.util.AESUtil;
import com.zmn.oms.third.gomegj.GmgjConsts;
import com.zmn.oms.third.gomegj.GmgjUtil;
import com.zmn.oms.third.gomegj.api.*;
import com.zmn.oms.third.gomegj.dto.GmgjRequestDTO;
import com.zmn.oms.third.gomegj.dto.GmgjResponseDTO;
import com.zmn.oms.third.gomegj.service.GmgjService;
import com.zmn.oms.business.interfaces.baidumap.BaiduMapBService;
import com.zmn.oms.zmn.business.interfaces.proxy.ProxyOrderBService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkQueryBService;
import com.zmn.oms.zmn.business.interfaces.work.autoflow.WorkFlowContextBService;
import com.zmn.oms.zmn.normal.business.interfaces.serviceitem.ZsNormalOrderServiceItemBService;
import com.zmn.pay.common.constant.PayConsts;
//import com.zmn.plat.common.dto.orderconfig.documentarycontent.DocumentaryContentDIO;
//import com.zmn.plat.common.dto.orderconfig.documentarycontent.DocumentaryContentDRO;
//import com.zmn.plat.dubbo.interfaces.orderconfig.documentarycontent.DocumentaryContentListRemoteService;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * 类描述：与国美美云保清洗的对接接口实现
 *
 * @author XieWenBing
 * @date 2019/12/02 18:00
 */

@Service
@Slf4j
public class GmgjServiceImpl implements GmgjService {

    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    protected AreaListRemoteService areaListRemoteService;

    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false)
    protected ChannelProductThirdListRemoteService channelProductThirdListRemoteService;

    @Autowired
    private OrderWorkService orderWorkService;

    @Autowired
    protected ZsOrderWorkQueryBService zsOrderWorkQueryBService;

    @Autowired
    private OrderRemarkService orderRemarkService;

    @Autowired
    private OrderDetailService orderDetailService;

    @Autowired
    private OrderRemarkDetailService orderRemarkDetailService;

    @Autowired
    private ProxyOrderBService proxyOrderBService;

    @Autowired
    private ZsNormalOrderServiceItemBService zsNormalOrderServiceItemBService;

    @Autowired
    private WorkFlowContextBService workFlowContextBService;

    @Autowired
    private OrderTrackBService orderTrackBService;

    @Autowired
    protected MessageSendAppService messageSendAppService;

    @Autowired
    private BaiduMapBService baiduMapBService;

    @Resource
    private RedisManager redisManager;

    @Resource
    private TaskManager taskManager;

    /**
     * 处理国美管家发送的订单消息（创建订单，取消订单，订单支付等）
     *
     * @param gmgjRequestDTO
     * @throws OmsBaseException
     */
    @Override
    public void handleOrderMsg(GmgjRequestDTO gmgjRequestDTO) throws OmsBaseException {

        if (Objects.isNull(gmgjRequestDTO)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR,"数据参数为空");
        }

        String orderMsg;
        if (GmgjConsts.TEST_SIGN.compareTo(gmgjRequestDTO.getSign()) != 0) {
            // 验证签名
            if (!GmgjUtil.verfiyOrderRequestSign(gmgjRequestDTO)) {
                throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR, "签名验证失败");
            }

            // 消息内容验证和解密
            if (StringUtil.isNullOrEmpty(gmgjRequestDTO.getBody())) {
                throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR, "消息内容为空");
            }

            try {
                orderMsg = AESUtil.decrypt(gmgjRequestDTO.getBody(), GmgjConsts.APP_SECRET);
            } catch (Exception e) {
                throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR, "解密消息失败");
            }
        } else {
            orderMsg = gmgjRequestDTO.getBody();
        }

        if (StringUtil.isNullOrEmpty(orderMsg)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR, "消息内容为空");
        }

        // JSON 转换
        JSONObject jsonObject;
        try {
            jsonObject = JSON.parseObject(orderMsg);
        } catch (Exception e) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR,"解析消息内容异常");
        }

        if (Objects.isNull(jsonObject)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR,"解析消息内容失败");
        }

        // 业务类型判断
        if (jsonObject.getIntValue("bussionType") != GmgjConsts.ORDER_BUSSION_TYPE_REPAIR) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR,"不支持的订单业务类型");
        }

        // 处理消息
        switch (gmgjRequestDTO.getMethod()) {
            // 创建订单
            case GmgjConsts.METHOD_CREATE_ORDER:
                this.handleCreateOrderMsg(jsonObject);
                break;

            // 取消订单
            case GmgjConsts.METHOD_CANCEL_ORDER:
                this.handleCancelOrderMsg(jsonObject);
                break;

            // 订单支付
            case GmgjConsts.METHOD_PAY_ORDER:
                this.handleOrderPayMsg(jsonObject);
                break;

            case GmgjConsts.METHOD_MODIFY_TIME:
                this.handleModifyTimeMsg(jsonObject);
                break;
            // 其他
            default:
                throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR,"错误的消息方法");
        }
    }

    /**
     * 同步渠道修改订单预约
     *
     * @param orderWorkLogChange
     * @throws OmsBaseException
     */
    @Override
    public void syncOrderDutytime(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 预约时间判断
        if (Objects.isNull(orderWorkLogChange.getDutyTime())) {
            throw new OmsBaseException("预约时间为空不同步");
        }

        String accessToken = this.getAccessToken();
        if (StringUtil.isNullOrEmpty(accessToken)) {
            log.info("【{}】<同步订单预约> 失败 - 获取不到token。", GmgjConsts.CHANNEL_NAME);
            throw new OmsBaseException("获取token失败");
        }

        // 生成同步数据
        GmgjSyncDutytimeModifyRequest syncDutytimeModifyRequest = new GmgjSyncDutytimeModifyRequest();
        syncDutytimeModifyRequest.setBussionType(GmgjConsts.ORDER_BUSSION_TYPE_REPAIR);
        syncDutytimeModifyRequest.setOrderId(orderWorkLogChange.getOuterId());

        Date dutyTime = orderWorkLogChange.getDutyTime();
        syncDutytimeModifyRequest.setServiceTime(DateUtil.toString(dutyTime,"yyyy-MM-dd"));
        syncDutytimeModifyRequest.setStartTime(DateUtil.toString(dutyTime,"HH:mm"));
        syncDutytimeModifyRequest.setEndTime(DateUtil.toString(dutyTime,"HH:mm"));

        // 发送请求
        String syncUrl = GmgjConsts.API_URL + String.format(GmgjConsts.PATH_ORDER_MODIFY_DUTYTIME,accessToken);
        String syncResponse = GmgjUtil.postHttpRequest(syncUrl,JSON.toJSONString(syncDutytimeModifyRequest));
        if (StringUtil.isNullOrEmpty(syncResponse)) {
            throw new OmsBaseException("发送同步预约时间请求失败");
        }

        log.info("【{}】同步预约时间，返回：【{}】",GmgjConsts.CHANNEL_NAME,syncResponse);

        // 解析同步结果信息
        analysisSyncResponse(syncResponse);
    }

    /**
     * 同步渠道取消订单
     *
     * @param orderWorkLogChange
     * @throws OmsBaseException
     */
    @Override
    public void syncCancelOrder(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 判断是否为渠道取消的订单，是则不处理
        if ((Objects.equals(orderWorkLogChange.getOperatorId(),Long.valueOf(OrderConsts.CHANNEL_ID_GOME_GJ_JDWX)) ||
                Objects.equals(orderWorkLogChange.getOperatorId(),Long.valueOf(OrderConsts.CHANNEL_ID_GOME_GJ_ZX))) &&
                (orderWorkLogChange.getOperatorType() == GlobalConsts.OPERATE_USER_TYPE_CHANNEL)) {
            throw new OmsBaseException("工单为渠道方取消，无需同步");
        }

        String accessToken = this.getAccessToken();
        if (StringUtil.isNullOrEmpty(accessToken)) {
            log.info("【{}】<同步订单取消> 失败 - 获取不到token。", GmgjConsts.CHANNEL_NAME);
            throw new OmsBaseException("获取token失败");
        }

        // 获取取消原因
        Long orderId = orderWorkLogChange.getOrderId();
        Long workId = orderWorkLogChange.getWorkId();
        String cancelReason = this.getOrderCancelReason(orderId,workId);

        // 生成同步数据
        GmgjSyncOrderCancelRequest syncOrderCancelRequest = new GmgjSyncOrderCancelRequest();
        syncOrderCancelRequest.setBussionType(GmgjConsts.ORDER_BUSSION_TYPE_REPAIR);
        syncOrderCancelRequest.setOrderId(orderWorkLogChange.getOuterId());
        syncOrderCancelRequest.setReasonCode(7);
        syncOrderCancelRequest.setReason(cancelReason);
        syncOrderCancelRequest.setCannelTime(DateUtil.getNowFormatted());

        // 发送请求
        String syncUrl = GmgjConsts.API_URL + String.format(GmgjConsts.PATH_ORDER_CANCEL,accessToken);
        String syncResponse = GmgjUtil.postHttpRequest(syncUrl,JSON.toJSONString(syncOrderCancelRequest));
        if (StringUtil.isNullOrEmpty(syncResponse)) {
            throw new OmsBaseException("发送同步订单取消请求失败");
        }

        log.info("【{}】同步取消订单，返回：【{}】",GmgjConsts.CHANNEL_NAME,syncResponse);

        // 解析同步结果信息
        this.analysisSyncResponse(syncResponse);
    }

    /**
     * 同步渠道订单派单
     *
     * @param orderWorkLogChange
     * @throws OmsBaseException
     */
    @Override
    public void syncOrderDistribute(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 获取token
        String accessToken = this.getAccessToken();
        if (StringUtil.isNullOrEmpty(accessToken)) {
            log.info("【{}】<同步订单派单> 失败 - 获取不到token。", GmgjConsts.CHANNEL_NAME);
            throw new OmsBaseException("获取token失败");
        }

        // 查找工单信息
        Long orderId = orderWorkLogChange.getOrderId();
        Long workId = orderWorkLogChange.getWorkId();

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId,workId);
        if(Objects.isNull(orderWork)) {
            throw new OmsBaseException("查找不到工单信息");
        }

        // 生成同步数据
        GmgjSyncOrderDistributeRequest syncOrderDistributeRequest = new GmgjSyncOrderDistributeRequest();
        syncOrderDistributeRequest.setBussionType(GmgjConsts.ORDER_BUSSION_TYPE_REPAIR);
        syncOrderDistributeRequest.setOrderId(orderWork.getOuterId());

        String masterName = orderWork.getMasterName();
        syncOrderDistributeRequest.setEngineerName(StringUtil.isNullOrEmpty(masterName) ? GmgjConsts.MASTER_DEFAULT_NAME:masterName);
        syncOrderDistributeRequest.setEngineerPhone(GmgjConsts.MASTER_PHONE);
        syncOrderDistributeRequest.setDispatchTime(DateUtil.getNowFormatted());

        // 发送请求
        String syncUrl = GmgjConsts.API_URL + String.format(GmgjConsts.PATH_ORDER_DISTRIBUTE,accessToken);
        String syncResponse = GmgjUtil.postHttpRequest(syncUrl,JSON.toJSONString(syncOrderDistributeRequest));
        if (StringUtil.isNullOrEmpty(syncResponse)) {
            throw new OmsBaseException("发送同步订单派单请求失败");
        }

        log.info("【{}】同步订单派单，返回：【{}】",GmgjConsts.CHANNEL_NAME,syncResponse);

        // 解析同步结果信息
        analysisSyncResponse(syncResponse);
    }

    /**
     * 同步渠道订单完成
     *
     * @param orderWorkLogChange
     * @throws OmsBaseException
     */
    @Override
    public void syncOrderComplete(OrderWorkLogChange orderWorkLogChange) throws OmsBaseException {

        // 获取token
        String accessToken = this.getAccessToken();
        if (StringUtil.isNullOrEmpty(accessToken)) {
            log.info("【{}】<同步订单完成> 失败 - 获取不到token。", GmgjConsts.CHANNEL_NAME);
            throw new OmsBaseException("获取token失败");
        }

        // 查找工单信息
        Long orderId = orderWorkLogChange.getOrderId();
        Long workId = orderWorkLogChange.getWorkId();

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId,workId);
        if(Objects.isNull(orderWork)) {
            throw new OmsBaseException("查找不到工单信息");
        }

        // 生成同步数据
        GmgjSyncOrderFinishRequest syncOrderFinishRequest = new GmgjSyncOrderFinishRequest();
        syncOrderFinishRequest.setBussionType(GmgjConsts.ORDER_BUSSION_TYPE_REPAIR);
        syncOrderFinishRequest.setOrderId(orderWork.getOuterId());
        syncOrderFinishRequest.setComplateTime(DateUtil.getNowFormatted());
        syncOrderFinishRequest.setOrderAmount(orderWork.getOriginalAmount());

        // 发送请求
        String syncUrl = GmgjConsts.API_URL + String.format(GmgjConsts.PATH_ORDER_FINISH,accessToken);
        String syncResponse = GmgjUtil.postHttpRequest(syncUrl,JSON.toJSONString(syncOrderFinishRequest));
        if (StringUtil.isNullOrEmpty(syncResponse)) {
            this.addLog(orderWork,"发送同步订单完成请求失败");
            throw new OmsBaseException("发送订单完成请求失败");
        }

        log.info("【{}】成功发送订单完成请求，返回：【{}】",GmgjConsts.CHANNEL_NAME,syncResponse);

        // 解析同步结果信息
        Integer errCode = this.analysisSyncResponse(syncResponse);
        if ( errCode != GmgjConsts.RESPONSE_CODE_SUCCESS) {
            this.addLog(orderWork,String.format("发送同步订单服务完成请求失败-%s",GmgjConsts.getErrorMsg(errCode)));
            throw new OmsBaseException("发送同步订单完成请求渠道方返回失败");
        }

        this.addLog(orderWork,"同步订单服务完成成功");
    }

    /**
     * 获取订单列表
     */
    @Override
    public void getOrderList() throws OmsBaseException {

        // 判断功能是否开启
        if (!GmgjConsts.POWER_ON) {
            log.info("【{}】<获取订单列表> 该功能没有开启。", GmgjConsts.CHANNEL_NAME);
            return;
        }

        String accessToken = this.getAccessToken();
        if (StringUtil.isNullOrEmpty(accessToken)) {
            log.info("【{}】<获取订单列表> 失败 - 获取不到token。", GmgjConsts.CHANNEL_NAME);
            throw new OmsBaseException("获取token失败");
        }

        // 生成请求数据
        GmgjGetOrderListRequest getOrderListRequest = new GmgjGetOrderListRequest();
        getOrderListRequest.setBussionType(GmgjConsts.ORDER_BUSSION_TYPE_REPAIR);
        getOrderListRequest.setEndTime(DateUtil.getNowFormatted());
        getOrderListRequest.setPageSize(GmgjConsts.MAX_PAGE_SIZE);
        getOrderListRequest.setOrderState(1);

        // 计算开始时间
        Long startTime = DateUtil.getNowTimestamp() - 900;
        getOrderListRequest.setStartTime(DateUtil.toString(startTime));

        String httpUrl = GmgjConsts.API_URL + String.format(GmgjConsts.PATH_GET_ORDER_LIST,accessToken);

        // 读取订单列表
        int pageIndex = 1;
        for ( pageIndex = 1; pageIndex <= GmgjConsts.MAX_PAGE_COUNT; pageIndex++) {

            getOrderListRequest.setPage(pageIndex);

            String httpResponse = GmgjUtil.postHttpRequest(httpUrl,JSON.toJSONString(getOrderListRequest));
            if (StringUtil.isNullOrEmpty(httpResponse)) {
                log.info("【{}】<获取订单列表>失败，Page【{}】- HTTP通信失败", GmgjConsts.CHANNEL_NAME,pageIndex);
                break;
            }

            log.info("【{}】<获取订单列表>，Page【{}】,Response【{}】", GmgjConsts.CHANNEL_NAME,pageIndex,httpResponse);
            GmgjGetOrderListResponse getOrderListResponse = null;
            try {
                getOrderListResponse = JSON.parseObject(httpResponse,GmgjGetOrderListResponse.class);
            } catch (Exception e) {
                log.info("【{}】<获取订单列表>失败，Page【{}】- 解析json异常", GmgjConsts.CHANNEL_NAME,pageIndex);
                break;
            }

            if (Objects.isNull(getOrderListResponse)) {
                log.info("【{}】<获取订单列表>失败，Page【{}】- 解析json错误", GmgjConsts.CHANNEL_NAME,pageIndex);
                break;
            }

            if (getOrderListResponse.getCode() != GmgjConsts.RESPONSE_CODE_SUCCESS) {
                log.info("【{}】<获取订单列表>失败，Page【{}】- 返回失败，消息：【{}】", GmgjConsts.CHANNEL_NAME,
                        pageIndex, GmgjConsts.getErrorMsg(getOrderListResponse.getCode()));
                break;
            }

            if (Objects.nonNull(getOrderListResponse.getData())) {
                for (GmgjOrderData  gmgjOrderData : getOrderListResponse.getData()) {

                    // 数据判断
                    if (Objects.isNull(gmgjOrderData) || StringUtil.isNullOrEmpty(gmgjOrderData.getOrderId())) {
                        continue;
                    }

                    // 订单是否存在判断
                    if (this.isChannelOrderExist(gmgjOrderData.getOrderId())) {
                        continue;
                    }

                    this.saveCreateOrderCacheData(gmgjOrderData.getOrderId(),"creating");

                    try {

                        // 订单审核
                        this.auditChannelOrder(gmgjOrderData.getOrderId());

                        // 创建订单
                        this.createOrder(gmgjOrderData);

                        this.saveCreateOrderCacheData(gmgjOrderData.getOrderId(),"created");

                    } catch (OmsBaseException e) {
                        log.info("【{}】<获取订单列表> 创建订单异常，渠道订单id【{}】，异常消息【{}】", GmgjConsts.CHANNEL_NAME,
                                gmgjOrderData.getOrderId(),e.getMessage());

                        this.saveCreateOrderCacheData(gmgjOrderData.getOrderId(),null);
                    }
                }
            }

            if (Objects.nonNull(getOrderListResponse.getPage().getRowCount())) {

                // 判断是否有更多的订单数据
                if ((pageIndex * GmgjConsts.MAX_PAGE_SIZE) > getOrderListResponse.getPage().getRowCount()) {
                    return;
                }
            }
        }

        if (pageIndex == 1) {
            throw new OmsBaseException("获取订单列表失败");
        }
    }

    /**
     * 根据渠道订单id创建订单
     *
     * @param channelOrderId
     * @throws OmsBaseException
     */
    @Override
    public void createOrderByChannelOrderId(String channelOrderId) throws OmsBaseException {

        if (StringUtil.isNullOrEmpty(channelOrderId)) {
            throw new OmsBaseException("参数错误-渠道订单Id不能为空");
        }

        if (isChannelOrderExist(channelOrderId)) {

            log.info("【{}】渠道订单 【{}】已经创建/正在创建中", GmgjConsts.CHANNEL_NAME, channelOrderId);
            return;
        }

        // 缓存创建，防止重复录单
        this.saveCreateOrderCacheData(channelOrderId,"creating");

        try {

            // 订单审核
            this.auditChannelOrder(channelOrderId);

            // 读取订单详情
            GmgjOrderData orderData = this.getChannelOrderDetail(channelOrderId);

            // 创建订单
            this.createOrder(orderData);

            this.saveCreateOrderCacheData(channelOrderId,"created");

        } catch (OmsBaseException e) {

            this.saveCreateOrderCacheData(channelOrderId,null);
            throw e;
        }
    }

    /**
     * 获取支付链接
     *
     * @param orderId
     * @param orderId
     * @return
     */
    @Override
    public String getPayUrl(Long orderId,Long workId) throws OmsBaseException {

        if (!GmgjConsts.POWER_ON) {
            throw new OmsBaseException("接口暂不支持，请确认");
        }

        log.info("【{}】获取支付URL,订单id为:【{}】", GmgjConsts.CHANNEL_NAME,orderId);

        // 参数判断
        if (Objects.isNull(orderId)) {
            throw new OmsBaseException("错误的订单id");
        }

        // 订单查找
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException("查找不到对应的订单");
        }

        // 渠道判断
        if (!orderWork.getChannelId().equals(OrderConsts.CHANNEL_ID_GOME_GJ_JDWX) &&
                !orderWork.getChannelId().equals(OrderConsts.CHANNEL_ID_GOME_GJ_ZX)) {
            throw new OmsBaseException("不是国美管家渠道的订单");
        }

        // 渠道id判断
        if (StringUtil.isNullOrEmpty(orderWork.getOuterId())) {
            throw new OmsBaseException("渠道订单id为null");
        }
        
        // 读取token
        String accessToken = this.getAccessToken();
        if (StringUtil.isNullOrEmpty(accessToken)) {
            log.info("【{}】<获取支付URL> 失败 - 获取不到token。", GmgjConsts.CHANNEL_NAME);
            throw new OmsBaseException("获取token失败");
        }

        // 同步订单服务明细
        if (!this.syncOrderServiceItem(accessToken,orderWork)) {

            // 发起跟单
            // this.autoUpdateOrderTrack(orderWork,OrderConsts.ORDER_TRACT_GMGJ_SECOND_PAY);
        }

        // 获取支付URL
        String payUrl = this.getOrderPayUrl(orderWork);
        if (StringUtil.isNullOrEmpty(payUrl)) {
            throw new OmsBaseException("获取渠道支付URL失败，请重试");
        }

        log.info("【{}】成功获取支付URL,订单id:【{}】，支付url:【{}】", GmgjConsts.CHANNEL_NAME,orderId,payUrl);
        return payUrl;
    }

    /**
     * 同步订单明细
     *
     * @param accessToken
     * @param orderWork
     * @throws OmsBaseException
     */
    public boolean syncOrderServiceItem(String accessToken,OrderWork orderWork) throws OmsBaseException {

        // 查找订单服务项
        List<ZsServiceItemVO> listServiceItem = zsNormalOrderServiceItemBService.findServiceItemVo(orderWork.getOrderId(),
                orderWork.getWorkId());
        if (Objects.isNull(listServiceItem) || listServiceItem.isEmpty()) {
            throw new OmsBaseException("订单查找不到服务项");
        }

        // 构造同步数据
        GmgjSyncOrderSeriveRequest gmgjSyncOrderSeriveRequest = new GmgjSyncOrderSeriveRequest();
        gmgjSyncOrderSeriveRequest.setBussionType(GmgjConsts.ORDER_BUSSION_TYPE_REPAIR);
        gmgjSyncOrderSeriveRequest.setOrderId(orderWork.getOuterId());

        // 查找订单服务项
        List<GmgjOrderServicePlan> listOrderServicePlan = new ArrayList<>();
        for (ZsServiceItemVO zsServiceItemVO : listServiceItem) {
            List<OrderServiceItem> serviceItemList = zsServiceItemVO.getServiceItemList();
            if (Objects.isNull(serviceItemList) || serviceItemList.isEmpty()) {
                continue;
            }

            for (OrderServiceItem orderServiceItem : serviceItemList) {

                GmgjOrderServicePlan gmgjOrderServicePlan = new GmgjOrderServicePlan();
                gmgjOrderServicePlan.setServiceNumber(orderServiceItem.getNumber());
                gmgjOrderServicePlan.setServicePlanPrice(orderServiceItem.getItemPrice());
                gmgjOrderServicePlan.setServicePlanName(orderServiceItem.getServItemName());
                gmgjOrderServicePlan.setTotalPrice(orderServiceItem.getTotalPrice());
                // TODO 服务项暂时都选服务措施
                gmgjOrderServicePlan.setServiceType(1);

                listOrderServicePlan.add(gmgjOrderServicePlan);
            }
        }

        if (NumberUtil.isNotNullOrZero(orderWork.getDiscountAmount())) {
            GmgjOrderServicePlan gmgjOrderServicePlan = new GmgjOrderServicePlan();
            gmgjOrderServicePlan.setServiceNumber(1);
            gmgjOrderServicePlan.setServicePlanPrice(-orderWork.getDiscountAmount());
            gmgjOrderServicePlan.setServicePlanName("优惠金额");
            gmgjOrderServicePlan.setTotalPrice(-orderWork.getDiscountAmount());
            // TODO 服务项暂时都选服务措施
            gmgjOrderServicePlan.setServiceType(1);

            listOrderServicePlan.add(gmgjOrderServicePlan);
        }

        gmgjSyncOrderSeriveRequest.setRepairServicePlanList(listOrderServicePlan);

        // 无需判断是否同步过明细，注视掉代码先
        // 读取redis缓存
//        String redisKey = String.format(RedisKeyConsts.GOME_GJ_ORDER_PAY_REDIS_KEY,orderWork.getOrderId());
//        String redisContent = redisManager.get(redisKey);

        // 判断是否保存redis 支付数据
/*        if (!StringUtil.isNullOrEmpty(redisContent)) {

            // 已有支付数据，相同则直接返回
            if (redisContent.compareTo(JSON.toJSONString(gmgjSyncOrderSeriveRequest)) == 0) {
                log.info("【{}】服务明细已经同步，无需再次同步",GmgjConsts.CHANNEL_NAME);
                return false;
            }

            // 允许多次调取服务项
             throw new OmsBaseException("国美管家渠道订单，不允许修改服务项并发起支付，请线下收费后，联系国美侧进行补单，再把钱支付到补单后的工单上，谢谢。注：此单非系统bug，无需反馈至研发中心");
        }*/

        // 发送请求
        String syncUrl = GmgjConsts.API_URL + String.format(GmgjConsts.PATH_ORDER_SERVICE,accessToken);
        String syncResponse = GmgjUtil.postHttpRequest(syncUrl,JSON.toJSONString(gmgjSyncOrderSeriveRequest));
        if (StringUtil.isNullOrEmpty(syncResponse)) {
            this.addLog(orderWork,"发送同步订单服务明细请求失败");
            throw new OmsBaseException("发送同步订单服务请求失败");
        }

        log.info("【{}】成功发送同步订单服务请求，返回：【{}】",GmgjConsts.CHANNEL_NAME,syncResponse);

        // 解析同步结果信息
        Integer errCode = this.analysisSyncResponse(syncResponse);
        if ( errCode != GmgjConsts.RESPONSE_CODE_SUCCESS) {
            this.addLog(orderWork,String.format("发送同步订单服务明细请求失败-%s",GmgjConsts.getErrorMsg(errCode)));
            throw new OmsBaseException("发送同步订单服务请求渠道方返回失败");
        }

        // 保存redis支付数据
//        redisManager.setex(redisKey,JSON.toJSONString(gmgjSyncOrderSeriveRequest),(3600 * 24 * 30));

        this.addLog(orderWork,"同步订单服务明细成功");
        return true;
    }

    /**
     * 获取订单支付url
     *
     * @param orderWork
     * @return
     * @throws OmsBaseException
     */
    protected String getOrderPayUrl(OrderWork orderWork) throws OmsBaseException{

        // 发送获取支付url请求
        String getPayUrl = String.format(GmgjConsts.PAY_URL,orderWork.getOuterId());

        log.info("【{}】发送获取支付请求URL，URL【{}】",GmgjConsts.CHANNEL_NAME,getPayUrl);

        String httpResponse= GmgjUtil.getHttpRequest(getPayUrl);
        if (StringUtil.isNullOrEmpty(httpResponse)) {
            this.addLog(orderWork,"发送获取订单补充支付URL请求失败");
            throw new OmsBaseException("发送获取订单支付URL请求失败");
        }

        // 解析返回结果
        try {

            JSONObject jsonObject = JSON.parseObject(httpResponse);
            if (Objects.isNull(jsonObject)) {
                this.addLog(orderWork,"获取订单补充支付URL失败-解析数据错误");
                throw new OmsBaseException("获取订单支付URL失败-解析数据错误");
            }

            if (jsonObject.getIntValue("rpco") != GmgjConsts.RESPONSE_CODE_SUCCESS) {
                log.info("【{}】获取订单支付URL失败--渠道方返回失败，【{}】【{}】",GmgjConsts.CHANNEL_NAME,
                        jsonObject.getIntValue("rpco"),jsonObject.getString("msg"));

                this.addLog(orderWork,String.format("获取订单补充支付URL返回失败,[%d],[%s]",jsonObject.getIntValue("rpco"),
                        jsonObject.getString("msg")));

                throw new OmsBaseException("获取订单支付URL失败-渠道方返回失败");
            }

            String body = jsonObject.getString("body");
            jsonObject = JSON.parseObject(body);
            if (Objects.isNull(jsonObject)) {
                this.addLog(orderWork,"获取订单补充支付URL失败-解析支付URL错误");
                throw new OmsBaseException("获取订单支付URL失败-解析数据错误");
            }

            return jsonObject.getString("payUrl");
        } catch (Exception e) {
            throw new OmsBaseException("解析获取订单支付URL请求应答异常");
        }
    }

    /**
     * 读取redis或通过http获得通信token
     *
     * @return
     */
    public String getAccessToken() {

        // 从redis中读取token信息
        GmgjTokenData tokenData = readRedisToken();

        do {

            // 对token信息进行判断
            if (Objects.isNull(tokenData)) {
                break;
            }

            Long nowTime = DateUtil.getNowTimestamp();
            if (nowTime >= tokenData.getEndTime()) {
                break;
            }

            // 返回保存的有效token
            return tokenData.getAccessToken();

        } while (false);

        String httpUrl;

        // 通过接口读取token信息
        if (Objects.isNull(tokenData) || StringUtil.isNullOrEmpty(tokenData.getReferToken())) {

            // 直接读取token
            GmgjGetTokenRequest getTokenRequest = new GmgjGetTokenRequest();
            getTokenRequest.setClientId(GmgjConsts.APP_ID);
            getTokenRequest.setGrantType("access_token");
            getTokenRequest.setTimestamp(String.valueOf(DateUtil.getNowTimestampMillis()));
            getTokenRequest.setUsername(GmgjConsts.APP_USERNAME);
            getTokenRequest.setPassword(DigestUtils.md5Hex(GmgjConsts.APP_PASSWORD));

            GmgjUtil.calcGetAccessTokenSign(getTokenRequest);

            httpUrl = GmgjConsts.API_URL + String.format(GmgjConsts.PATH_GET_TOKEN, getTokenRequest.getClientId(),
                    getTokenRequest.getUsername(), getTokenRequest.getPassword(), getTokenRequest.getTimestamp(),
                    getTokenRequest.getSign());

        } else {

            // 刷新token
            GmgjRefreshTokenRequest refreshTokenRequest = new GmgjRefreshTokenRequest();
            refreshTokenRequest.setClientId(GmgjConsts.APP_ID);
            refreshTokenRequest.setClientSecret(GmgjConsts.APP_SECRET);
            refreshTokenRequest.setRefreshToken(tokenData.getReferToken());

            httpUrl = GmgjConsts.API_URL + String.format(GmgjConsts.PATH_REFRESH_TOKEN,refreshTokenRequest.getClientId(),
                    refreshTokenRequest.getClientSecret(),refreshTokenRequest.getRefreshToken());
        }

        String tokenResponse = GmgjUtil.postHttpRequest(httpUrl,"");
        if (StringUtil.isNullOrEmpty(tokenResponse)) {
            log.info("【{}】获取token失败，url：【{}】，params：【{}】",GmgjConsts.CHANNEL_NAME,httpUrl);
            return null;
        }

        // 解析返回的token信息
        log.info("【{}】获取token应答，response：【{}】",GmgjConsts.CHANNEL_NAME,tokenResponse);
        GmgjGetTokenResponse gmgjGetTokenResponse;
        try {
            gmgjGetTokenResponse = JSON.parseObject(tokenResponse,GmgjGetTokenResponse.class);
        } catch (Exception e) {
            log.info("【{}】读取token信息异常",GmgjConsts.CHANNEL_NAME);
            return null;
        }

        if (Objects.isNull(gmgjGetTokenResponse) || Objects.isNull(gmgjGetTokenResponse.getData()) ||
                gmgjGetTokenResponse.getCode() != GmgjConsts.RESPONSE_CODE_SUCCESS ) {
            log.info("【{}】读取token信息失败",GmgjConsts.CHANNEL_NAME);
            return null;
        }

        tokenData = gmgjGetTokenResponse.getData();

        // 保存token信息
        this.saveRedisToken(tokenData);

        return tokenData.getAccessToken();
    }

    /**
     * 处理创建订单消息
     *
     * @param jsonObject
     * @throws OmsBaseException
     */
    protected void handleCreateOrderMsg(JSONObject jsonObject) throws OmsBaseException {

        // 获取渠道订单id
        String channelOrderId = jsonObject.getString("orderId");
        if (StringUtil.isNullOrEmpty(channelOrderId)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR,"orderId为空");
        }

        // 查找对应的订单
        ZsOrderWorkVO orderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterIdAndChannelIds(channelOrderId,
                new ArrayList<Integer>(){{add(OrderConsts.CHANNEL_ID_GOME_GJ_JDWX);add(OrderConsts.CHANNEL_ID_GOME_GJ_ZX);}});
        if (Objects.nonNull(orderWorkVO)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR,String.format("订单已经存在,渠道订单Id=[%s]", channelOrderId));
        }

        // 将创建工单放入任务队列
        addCreateOrderJob(channelOrderId);
    }

    /**
     * 添加创建订单任务
     *
     * @param channelOrderId
     */
    void addCreateOrderJob(String channelOrderId) {

        // 30秒后执行 创建订单
        Job job = new Job();
        job.setTaskId(TaskConsts.TASK_ID_GMGJ_ADD_CREATE_JOB + ":" + channelOrderId);
        job.setParam(TaskManager.SHARD_FIELD, TaskConsts.TASK_ID_GMGJ_ADD_CREATE_JOB);
        job.setParam("outerId", channelOrderId);
        job.setRepeatCount(1);
        Date dateRun = DateUtil.addSecond(DateUtil.getNow(), 30);
        job.setTriggerDate(dateRun);

        taskManager.submitTask2(job);
    }

    /**
     * 获取订单详情
     *
     * @param outerId
     * @throws OmsBaseException
     */
    protected GmgjOrderData getChannelOrderDetail(String outerId) throws OmsBaseException {

        // 获取token
        String accessToken = this.getAccessToken();
        if (StringUtil.isNullOrEmpty(accessToken)) {
            log.info("【{}】<同步订单取消> 失败 - 获取不到token。", GmgjConsts.CHANNEL_NAME);
            throw new OmsBaseException("获取token失败");
        }

        // 生成请求数据
        GmgjGetOrderDetailRequest getOrderDetailRequest = new GmgjGetOrderDetailRequest();
        getOrderDetailRequest.setBussionType(GmgjConsts.ORDER_BUSSION_TYPE_REPAIR);
        getOrderDetailRequest.setOrderId(outerId);

        // 发送请求
        String syncUrl = GmgjConsts.API_URL + String.format(GmgjConsts.PATH_GET_ORDER_DETAIL,accessToken);
        String syncResponse = GmgjUtil.postHttpRequest(syncUrl,JSON.toJSONString(getOrderDetailRequest));
        if (StringUtil.isNullOrEmpty(syncResponse)) {
            throw new OmsBaseException("发送获取订单详情请求失败");
        }

        log.info("【{}】获取订单详情，返回：【{}】",GmgjConsts.CHANNEL_NAME,syncResponse);

        // 解析请求结果信息
        GmgjGetOrderDetailResponse getOrderDetailResponse = null;
        try {
            getOrderDetailResponse = JSON.parseObject(syncResponse,GmgjGetOrderDetailResponse.class);
        } catch (Exception e) {
            throw new OmsBaseException("解析返回结果异常");
        }

        if (Objects.isNull(getOrderDetailResponse)) {
            throw new OmsBaseException("解析返回结果失败");
        }

        if (getOrderDetailResponse.getCode() != GmgjConsts.RESPONSE_CODE_SUCCESS) {
            throw new OmsBaseException(String.format("渠道返回失败，返回结果码：%d",getOrderDetailResponse.getCode()));
        }

        return getOrderDetailResponse.getData();
    }

    /**
     * 发送订单审核
     *
     * @param outerId
     * @throws OmsBaseException
     */
    protected void auditChannelOrder(String outerId) throws OmsBaseException {

        // 获取token
        String accessToken = this.getAccessToken();
        if (StringUtil.isNullOrEmpty(accessToken)) {
            log.info("【{}】<订单审核> 失败 - 获取不到token。", GmgjConsts.CHANNEL_NAME);
            throw new OmsBaseException("获取token失败");
        }

        // 生成请求数据
        GmgjAuditOrderRequest auditOrderRequest = new GmgjAuditOrderRequest();
        auditOrderRequest.setBussionType(GmgjConsts.ORDER_BUSSION_TYPE_REPAIR);
        auditOrderRequest.setOrderId(outerId);

        // 发送请求
        String syncUrl = GmgjConsts.API_URL + String.format(GmgjConsts.PATH_AUDIT_ORDER,accessToken);
        String syncResponse = GmgjUtil.postHttpRequest(syncUrl,JSON.toJSONString(auditOrderRequest));
        if (StringUtil.isNullOrEmpty(syncResponse)) {
            throw new OmsBaseException("发送订单审核请求失败");
        }

        log.info("【{}】订单审核，返回：【{}】",GmgjConsts.CHANNEL_NAME,syncResponse);

        // 解析请求结果信息
        if (analysisSyncResponse(syncResponse) != GmgjConsts.RESPONSE_CODE_SUCCESS ) {
            throw new OmsBaseException(String.format("订单审核渠道方平台返回失败"));
        }
    }

    /**
     * 创建订单
     *
     * @param orderData
     * @throws OmsBaseException
     */
    protected void createOrder(GmgjOrderData orderData) throws OmsBaseException {

        if (Objects.isNull(orderData)) {
            throw new OmsBaseException("创建订单失败，渠道订单数据为NULL");
        }

        CreateOrderDTO createOrderDTO = new CreateOrderDTO();
        if (Objects.isNull(createOrderDTO)) {
            throw new OmsBaseException("创建订单异常");
        }

        // 渠道信息
        createOrderDTO.setOuterId(orderData.getOrderId());
        createOrderDTO.setOuterData(JSON.toJSONString(orderData));

        if (Objects.equals(orderData.getRepairType(), GmgjConsts.REPAIR_TYPE_OUT_INSURE)) {
            createOrderDTO.setChannelId(OrderConsts.CHANNEL_ID_GOME_GJ_JDWX);
        } else {
            createOrderDTO.setChannelId(OrderConsts.CHANNEL_ID_GOME_GJ_ZX);
        }

        // 联系人信息
        createOrderDTO.setContactName(orderData.getCustomerName());
        createOrderDTO.setTelephone(orderData.getCustomerPhone());
        createOrderDTO.setRemark(orderData.getRemark());
        createOrderDTO.setGender(GlobalDict.GENDER_NO);

        // 预约时间
        this.setDutytimeOfCreateOrderDTO(createOrderDTO, orderData);

        // 平台、操作者等信息
        createOrderDTO.setPlat(GlobalConsts.PLAT_MARK_ZMN);
        createOrderDTO.setDisableDiscard(GlobalConsts.NO);
        createOrderDTO.setOperator("系统");
        createOrderDTO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        createOrderDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
        createOrderDTO.setInputType(OrderConsts.ORDER_INPUT_TYPE_API);

        // 地址信息
        createOrderDTO.setAddress(orderData.getCustomerAddr());
        createOrderDTO.setStreet(orderData.getAddrStreet());

        // 城市id
        this.setCityIdOfCreateOrderDTO(createOrderDTO, orderData);

        // 产品id
        this.setProductOfCreateOrderDTO(createOrderDTO, orderData);

        // 操作日志
        this.setLogRemarkOfCreateOrderDTO(createOrderDTO, orderData);

        // 预付信息
        Integer channelPrepayAmount = Optional.ofNullable(orderData.getPrePrice()).orElse(0);
        if (NumberUtil.isNotNullOrZero(channelPrepayAmount) &&
                Objects.equals(orderData.getPayStatus(), GmgjConsts.ORDER_PAY_TYPE_DONE)) {
            createOrderDTO.setChannelPrepayAmount(channelPrepayAmount);
            createOrderDTO.setChannelPrepayStatus(PayConsts.PAY_STATUS_DONE);
            createOrderDTO.setPrepayTime(DateUtil.getNow());
        }

        // 创建订单
        OrderBO orderBO;
        try {
            orderBO = proxyOrderBService.createOrder(createOrderDTO);

            log.info("【{}】保存订单成功 OrderId:[{}]", GmgjConsts.CHANNEL_NAME, orderBO.getOrder().getOrderId());
        } catch (Exception exception) {
            log.error("【{}】保存订单失败 消息:[{}]", GmgjConsts.CHANNEL_NAME, exception.getMessage());
            throw new OmsBaseException(String.format("创建订单失败-%s",exception.getMessage()));
        }

        // 工单自动流转
        OrderWork orderWork = orderBO.getOrderWork();
        workFlowContextBService.autoFlow(orderWork.getOrderId(), orderWork.getWorkId());
    }

    /**
     * 读取预约信息
     *
     * @param gmgjOrderData
     * @return
     */
    protected void setDutytimeOfCreateOrderDTO(CreateOrderDTO createOrderDTO, GmgjOrderData gmgjOrderData) {

        Date dutyTime = null;

        do {

            // 判断预约时间数据
            if (StringUtil.isNullOrEmpty(gmgjOrderData.getBookDay()) || StringUtil.isNullOrEmpty(gmgjOrderData.getBookTimeStart())) {
                break;
            }

            // 判断预约的日期
            dutyTime = DateUtil.parse(gmgjOrderData.getBookDay());
            if (Objects.isNull(dutyTime)) {
                break;
            }

            // 组成预约时间
            String bookDate = gmgjOrderData.getBookDay().substring(0,gmgjOrderData.getBookDay().indexOf(' ') + 1);
            String bookTime  = bookDate + gmgjOrderData.getBookTimeStart();

            // 判断预约时间是否小于当前时间
            dutyTime = DateUtil.parse(bookTime);
            if (DateUtil.toTimestamp(dutyTime) < DateUtil.getNowTimestamp()) {
                bookTime = bookDate + gmgjOrderData.getBookTimeEnd();
                dutyTime = DateUtil.parse(bookTime);
            }
        } while(false);

        createOrderDTO.setDutyTime(dutyTime);
    }

    /**
     * 创建订单操作日志
     * @param orderData
     * @return
     */
    protected void setLogRemarkOfCreateOrderDTO(CreateOrderDTO createOrderDTO, GmgjOrderData orderData) {

        // 操作日志
        StringBuilder sbLogRemark = new StringBuilder();
        sbLogRemark.append("<br/> 渠道订单id：").append(orderData.getOrderId())
                .append("<br/> 产品信息：").append(Optional.ofNullable(orderData.getCategoryName()).orElse("")).append(" - ")
                .append(Optional.ofNullable(orderData.getGoodsName()).orElse(""))
                .append("<br> 地址信息：").append(Optional.ofNullable(orderData.getAddrProvince()).orElse("")).append(" ")
                .append(Optional.ofNullable(orderData.getAddrCity()).orElse("")).append(" ")
                .append(Optional.ofNullable(orderData.getAddrRegion()).orElse("")).append(" ")
                .append(Optional.ofNullable(orderData.getAddrStreet()).orElse("")).append(" ")
                .append(Optional.ofNullable(orderData.getCustomerAddr()).orElse("")).append(" ")
                .append("<br> 预付金额：").append(MoneyUtil.parseToYuan(Optional.ofNullable(orderData.getPrePrice()).orElse(0))).append("元");

        createOrderDTO.setOperatorLogRemark(sbLogRemark.toString());
    }

    /**
     * 设置城市id
     * @param createOrderDTO
     * @param orderData
     */
    protected  void setCityIdOfCreateOrderDTO(CreateOrderDTO createOrderDTO, GmgjOrderData orderData) {

        StringBuilder sbAddress = new StringBuilder();
        sbAddress.append(Optional.ofNullable(orderData.getAddrProvince()).orElse(""))
                .append(Optional.ofNullable(orderData.getAddrCity()).orElse(""))
                .append(Optional.ofNullable(orderData.getAddrRegion()).orElse(""))
                .append(Optional.ofNullable(orderData.getAddrStreet()).orElse(""))
                .append(Optional.ofNullable(orderData.getCustomerAddr()).orElse(""));

        // 缺省设置为重庆
        createOrderDTO.setCityId(500100);
        createOrderDTO.setAddress(sbAddress.toString());

        // 查找经纬度
        LngLatLocation areaLocation = baiduMapBService.location(sbAddress.toString());
        if (Objects.isNull(areaLocation)) {
            return;
        }

        // 经纬度查找区域信息
        ResponseDTO<AreaDRO> areaResponse = areaListRemoteService.getAreaByLatAndLng(Double.valueOf(areaLocation.getLng()),Double.valueOf(areaLocation.getLat()));
        if (Objects.isNull(areaResponse) || !areaResponse.isSuccess() || Objects.isNull(areaResponse.getData())) {
            return;
        }

        // 城市id
        createOrderDTO.setCityId(Integer.valueOf(areaResponse.getData().getParentId()));

        // 设置经纬度
        Double longitude = Double.valueOf(areaResponse.getData().getLongitude());
        Double latitude = Double.valueOf(areaResponse.getData().getLatitude());
        createOrderDTO.setLongitude(longitude);
        createOrderDTO.setLatitude(latitude);
    }

    /**
     * 设置产品信息
     * @param createOrderDTO
     * @param orderData
     */
    protected void setProductOfCreateOrderDTO(CreateOrderDTO createOrderDTO, GmgjOrderData orderData) {

        // 查找产品id
        Integer productId = 0;
        ResponseDTO<List<ProductBaseDRO>> servProductListResponseDTO =
                channelProductThirdListRemoteService.listByChannelIdAndProductParentIdAndSubId(createOrderDTO.getChannelId(),
                        orderData.getGoodsCode(),null);
        if (!servProductListResponseDTO.isSuccess() || Objects.isNull(servProductListResponseDTO.getData()) ||
                servProductListResponseDTO.getData().isEmpty()) {
            log.info("【{}】调用#channelProductMapListRemoteService#listByChannelIdAndProductParentIdAndProductSubId#失败，参数【{}】返回结果【{}】",
                    createOrderDTO.getChannelId(), orderData.getGoodsCode(), servProductListResponseDTO.toString());

            productId = OrderConsts.CHANNEL_DISABLED_PRODUCT_ID;
        } else {

            productId = servProductListResponseDTO.getData().get(0).getProductId();
        }

        // 产品信息
        OrderProductDTO orderProduct = new OrderProductDTO();
        orderProduct.setProductId(productId);
        orderProduct.setNumber(1);

        List<OrderProductDTO> list = new LinkedList<>();
        list.add(orderProduct);
        createOrderDTO.setOrderProductList(list);
    }

    /**
     * 处理取消订单消息
     *
     * @param jsonObject
     * @throws OmsBaseException
     */
    protected void handleCancelOrderMsg(JSONObject jsonObject) throws OmsBaseException {

        // 获取渠道订单id
        String outerId = jsonObject.getString("orderId");
        if (StringUtil.isNullOrEmpty(outerId)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR,"orderId为空");
        }

        // 查找对应的订单
        ZsOrderWorkVO orderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterIdAndChannelIds(outerId,
                new ArrayList<Integer>(){{add(OrderConsts.CHANNEL_ID_GOME_GJ_JDWX);add(OrderConsts.CHANNEL_ID_GOME_GJ_ZX);}});
        if (Objects.isNull(orderWorkVO)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_ORDER_NO_EXIST,String.format("找不到对应的订单数据,渠道订单Id=[%s]", outerId));
        }

        log.info("【{}】取消订单：订单Id:[{}]，OuterId:[{}]", GmgjConsts.CHANNEL_NAME,orderWorkVO.getOrderId(), outerId);

        // 取消订单
        CancelOrderDTO cancelOrderDTO = new CancelOrderDTO();
        cancelOrderDTO.setOrderId(orderWorkVO.getOrderId());
        cancelOrderDTO.setOuterId(outerId);
        cancelOrderDTO.setChannelId(orderWorkVO.getChannelId());
        cancelOrderDTO.setOperatorId((long)orderWorkVO.getChannelId());
        cancelOrderDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
        cancelOrderDTO.setRemark("渠道取消订单");
        cancelOrderDTO.setOperator("渠道");

        try {
            proxyOrderBService.cancelOrder(cancelOrderDTO);
        } catch (OmsBaseException omsBaseException) {
            log.error("【{}】取消订单失败 消息:[{}]", GmgjConsts.CHANNEL_NAME, omsBaseException.getMessage());
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_SYSTEM_ERROR,"取消订单失败");
        }
    }

    /**
     * 处理订单支付消息
     *
     * @param jsonObject
     * @throws OmsBaseException
     */
    protected void handleOrderPayMsg(JSONObject jsonObject) throws OmsBaseException {

        // 获取渠道订单id
        String channelOrderId = jsonObject.getString("orderId");
        if (StringUtil.isNullOrEmpty(channelOrderId)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR,"orderId为空");
        }

        // 支付金额 - 分
        Integer payMoney = Optional.ofNullable(jsonObject.getInteger("payMoney")).orElse(0) +
                Optional.ofNullable(jsonObject.getInteger("couponPrice")).orElse(0);
        if (NumberUtil.isNullOrZero(payMoney)) {
            log.info("【{}】 收到订单支付消息,渠道订单id:[{}]，支付金额为0，不处理",GmgjConsts.CHANNEL_NAME, channelOrderId);
            return;
        }

        // 更新订单金额信息
        ZsOrderWorkVO orderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterIdAndChannelIds(channelOrderId,
                new ArrayList<Integer>(){{add(OrderConsts.CHANNEL_ID_GOME_GJ_JDWX);add(OrderConsts.CHANNEL_ID_GOME_GJ_ZX);}});
        if (Objects.isNull(orderWorkVO)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_ORDER_NO_EXIST,String.format("找不到对应的订单数据,渠道订单Id=[%s]", channelOrderId));
        }

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderWorkVO.getOrderId(), orderWorkVO.getWorkId());
        if (Objects.isNull(orderWork)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_ORDER_NO_EXIST,String.format("找不到对应的订单,渠道订单Id=[%s]", channelOrderId));
        }

        // 是否抵扣师傅收款额
        boolean subMasterAmount = true;
        if (Optional.ofNullable(orderWork.getMasterAmount()).orElse(0) <= 0) {
            // 不存在师傅收款额时（比如师傅上门报价前，用户在渠道方支付尾款），不抵扣师傅收款额，只记录渠道代收金额
            subMasterAmount = false;
        }

        log.info("【{}】 收到订单支付消息,渠道订单id:[{}]，支付金额:[{}]",GmgjConsts.CHANNEL_NAME, channelOrderId, payMoney);

        PayOrderDTO payOrderDTO = new PayOrderDTO();
        payOrderDTO.setChannelId(orderWork.getChannelId());
        payOrderDTO.setOrderId(orderWork.getOrderId());
        payOrderDTO.setWorkId(orderWork.getWorkId());
        payOrderDTO.setPayTime(new Date());
        payOrderDTO.setSubMasterAmount(subMasterAmount);

        // 转换为分,并且需减去原来的预付款，消息通知的金额为实际支付的所有金额
        Integer oldChannelPrepayAmount = Optional.ofNullable(orderWork.getChannelPrepayAmount()).orElse(0);
        StringBuilder remarkBuilder = new StringBuilder();

        payOrderDTO.setPayAmount(payMoney);
        payOrderDTO.setOrderPayType(OrderConsts.API_ORDER_PAY_TYPE_CHANNEL_MASTER_AMOUNT);

        // 抵扣师傅收款额后，将订单置为完成状态，否则不更改订单状态
        payOrderDTO.setCompleteOrder(subMasterAmount);

        remarkBuilder.append("原预付金额：").append(MoneyUtil.parseToYuanStr(oldChannelPrepayAmount)).append("元，")
                .append("补差金额：").append(MoneyUtil.parseToYuanStr(payMoney)).append("元；");

        if (subMasterAmount) {
            this.pushPayMessage(orderWork,payMoney);
        } else {
            if (CollectionUtils.isEmpty(zsNormalOrderServiceItemBService.listByOrderId(orderWork.getOrderId()))) {
                remarkBuilder.append("工单未选择服务项；");
            }
        }

        String logRemark = remarkBuilder.toString();
        payOrderDTO.setOperatorLogRemark(logRemark);
        payOrderDTO.setOperatorRemark(logRemark);

        try {
            proxyOrderBService.payOrder(payOrderDTO);
        } catch (Exception e) {

            log.error("【{}】更新订单金额失败：{}", GmgjConsts.CHANNEL_NAME, e.getMessage());
            Integer allChannelPayAmount = oldChannelPrepayAmount + payMoney;

            addLog(orderWork,String.format("渠道订单金额变更，原支付金额：%.2f，现支付金额：%.2f,总支付金额：%.2f，修改订单金额异常：%s",
                    oldChannelPrepayAmount.doubleValue()/100,
                    payMoney.doubleValue()/100,
                    allChannelPayAmount.doubleValue()/100,
                    e.getMessage()));

            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_SYSTEM_ERROR, "系统处理支付消息失败");
        }
    }

    /**
     * 处理订单改约消息
     *
     * @param jsonObject
     * @throws OmsBaseException
     */
    protected void handleModifyTimeMsg(JSONObject jsonObject) throws OmsBaseException {

        // 获取渠道订单id
        String channelOrderId = jsonObject.getString("orderId");
        if (StringUtil.isNullOrEmpty(channelOrderId)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR, "orderId为空");
        }

        // 预约时间
        String dayTime = jsonObject.getString("serviceTime");
        String startTime = jsonObject.getString("startTime");
        String endTime = jsonObject.getString("endTime");
        if (StringUtil.isNullOrEmpty(dayTime) || (StringUtil.isNullOrEmpty(startTime) && StringUtil.isNullOrEmpty(endTime))) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR, "参数不完整");
        }

        log.info("【{}】收到订单改约消息，渠道订单id【{}】,预约时间：【{} {}-{}】", GmgjConsts.CHANNEL_NAME, channelOrderId, dayTime, startTime, endTime);
        // 查找订单
        ZsOrderWorkVO orderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterIdAndChannelIds(channelOrderId,
                new ArrayList<Integer>() {{
                    add(OrderConsts.CHANNEL_ID_GOME_GJ_JDWX);
                    add(OrderConsts.CHANNEL_ID_GOME_GJ_ZX);
                }});
        if (Objects.isNull(orderWorkVO)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_ORDER_NO_EXIST, String.format("找不到对应的订单数据,渠道订单Id=[%s]", channelOrderId));
        }

        // 预约时间转换
        StringBuilder sbTime = new StringBuilder().append(dayTime).append(" ").append(StringUtil.isNullOrEmpty(startTime) ? endTime : startTime);
        Date dutyTime = DateUtil.parse(sbTime.toString(),"yyyy-MM-dd HH:mm");
        if (Objects.isNull(dutyTime)) {
            throw new OmsBaseException(GmgjConsts.RESPONSE_CODE_VALIDATE_ERROR, "参数不正确");
        }

        UpdateOrderDTO updateOrderDTO = new UpdateOrderDTO();
        updateOrderDTO.setOrderId(orderWorkVO.getOrderId());
        updateOrderDTO.setWorkId(orderWorkVO.getWorkId());
        updateOrderDTO.setDutyTime(dutyTime);

        try {
            proxyOrderBService.updateOrder(updateOrderDTO);
        } catch (OmsBaseException omsBaseException) {
            log.error("【{}】更新订单预约时间失败 消息:[{}]", GmgjConsts.CHANNEL_NAME, omsBaseException.getMessage());
            throw new OmsBaseException("改约失败");
        }

        // 记录日志
        String orderLog = String.format("渠道修改预约时间，期望日期：%s，开始时间：%s，结束时间：%s, 改约时间：%s",
                dayTime,startTime,endTime,DateUtil.toString(dutyTime));
        this.addLog(orderWorkVO, orderLog);
    }

    /**
     * 读取redis中保存的token
     *
     * @return
     */
    protected GmgjTokenData readRedisToken() {

        String redisContent = redisManager.get(RedisKeyConsts.GOME_GJ_TOKEN_REDIS_KEY);
        if (StringUtil.isNullOrEmpty(redisContent)) {
            return null;
        }

        GmgjTokenData tokenData = null;

        try {
            tokenData = JSON.parseObject(redisContent,GmgjTokenData.class);
        } catch (Exception e) {
            log.info("【{}】解析redis中的token数据异常",GmgjConsts.CHANNEL_NAME);
        }

        return tokenData;
    }

    /**
     * 保存token信息到redis中
     *
     * @param tokenData
     */
    protected void saveRedisToken(GmgjTokenData tokenData) {

        if (Objects.isNull(tokenData)) {
            return;
        }

        String redisContent = JSON.toJSONString(tokenData);
        Long timeOut = 0L;

        // 有效时间
        if (!NumberUtil.isNullOrZero(tokenData.getEndTime())) {
            timeOut = tokenData.getEndTime() - DateUtil.getNowTimestamp();
        }

        // 保存
        redisManager.setex(RedisKeyConsts.GOME_GJ_TOKEN_REDIS_KEY, redisContent, timeOut > 0 ? timeOut.intValue() : (3600 * 24));
    }

    /**
     * 订单状态同步请求返回数据进行解析
     *
     * @param response
     * @throws OmsBaseException
     */
    protected Integer analysisSyncResponse(String response) throws OmsBaseException {

        // 解析返回的JSON数据
        try {
            GmgjResponseDTO responseDTO = JSON.parseObject(response,GmgjResponseDTO.class);
            if (Objects.isNull(responseDTO)) {
                throw new OmsBaseException("解析同步请求返回数据失败");
            }

            log.info("【{}】订单消息同步结果，code:【{}】,msg:【{}】",GmgjConsts.CHANNEL_NAME, responseDTO.getCode(), GmgjConsts.getErrorMsg(responseDTO.getCode()));

            return responseDTO.getCode();
        } catch (Exception e) {
            throw new OmsBaseException("解析同步请求返回数据异常");
        }
    }

    /**
     * 得到订单取消的原因
     *
     * @param orderId
     * @param workId
     * @return
     */
    protected String getOrderCancelReason(Long orderId,Long workId) {

        // 设置默认取消缘由
        String cancelReason = "订单被强制取消";
        if (NumberUtil.isNullOrZero(orderId) || NumberUtil.isNullOrZero(workId)) {
            return cancelReason;
        }

        OrderRemark orderRemark = orderRemarkService.findByOrderIdAndType(orderId, workId, OrderConsts.ORDER_REMARK_TYPE_CANCEL);
        if (Objects.isNull(orderRemark)) {
            return cancelReason;
        }

        if (!StringUtil.isNullOrEmpty(orderRemark.getContent())) {
            cancelReason = orderRemark.getContent();
            return cancelReason;
        }

       List<OrderRemarkDetail> remarkDetailList = orderRemarkDetailService.listOrderRemarkDetailByRemarkId(orderId, workId,
                    orderRemark.getRemarkId());
        if (!CollectionUtils.isEmpty(remarkDetailList)) {
            cancelReason = remarkDetailList.get(0).getMapName();
        }

        return cancelReason;
    }

    /**
     * 向师傅APP端推送消息支付成功消息
     * @param orderWork
     * @param payAmount
     */
    private void pushPayMessage(OrderWork orderWork,Integer payAmount) {

        if (Objects.isNull(orderWork)) {
            return;
        }

        Map<String, Object> params = Maps.newHashMap();
        params.put("order_id", String.valueOf(orderWork.getOrderId()));
        params.put("work_id", String.valueOf(orderWork.getWorkId()));
        params.put("amount", String.valueOf(AmountUtil.fen2Yuan(payAmount)));
        messageSendAppService.pushAppMessageInfo(MessageRuleIdConsts.PUSH_MSG_RULEID_ORDER_PAY,JSON.toJSONString(params),orderWork);
    }

    /**
     *  添加日志记录
     * @param orderWork
     * @param errLog
     * @throws OmsBaseException
     */
    private void addLog(OrderWork orderWork,String errLog) throws OmsBaseException {

        OrderLogDTO orderLogDTO = new OrderLogDTO();
        orderLogDTO.setOrderId(orderWork.getOrderId());
        orderLogDTO.setOuterId(orderWork.getOuterId());
        orderLogDTO.setChannelId(orderWork.getChannelId());
        orderLogDTO.setOperatorId((long)orderWork.getChannelId());
        orderLogDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
        orderLogDTO.setType(OrderLogConsts.ORDER_LOG_TYPE_CHANNEL_REMARK);
        orderLogDTO.setOperatorLogRemark(errLog);

        proxyOrderBService.addOrderLog(orderLogDTO);
    }

    /**
     *  添加日志记录
     * @param orderWorkVO
     * @param errLog
     * @throws OmsBaseException
     */
    private void addLog(ZsOrderWorkVO orderWorkVO,String errLog) throws OmsBaseException {

        OrderLogDTO orderLogDTO = new OrderLogDTO();
        orderLogDTO.setOrderId(orderWorkVO.getOrderId());
        orderLogDTO.setOuterId(orderWorkVO.getOuterId());
        orderLogDTO.setChannelId(orderWorkVO.getChannelId());
        orderLogDTO.setOperatorId((long)orderWorkVO.getChannelId());
        orderLogDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
        orderLogDTO.setType(OrderLogConsts.ORDER_LOG_TYPE_CHANNEL_REMARK);
        orderLogDTO.setOperatorLogRemark(errLog);

        proxyOrderBService.addOrderLog(orderLogDTO);
    }

    /**
     * 判断订单是否已经创建或创建中
     * @param channelOrderId
     * @return
     */
    private boolean isChannelOrderExist(String channelOrderId) {

        // 查询数据库订单是否存在
        ZsOrderWorkVO zsOrderWorkVO = zsOrderWorkQueryBService.findOrderWorkByOuterIdAndChannelIds(channelOrderId,
                new ArrayList<Integer>(){{add(OrderConsts.CHANNEL_ID_GOME_GJ_JDWX);add(OrderConsts.CHANNEL_ID_GOME_GJ_ZX);}});
        if (Objects.nonNull(zsOrderWorkVO)) {
            return true;
        }

        String redisKey = String.format(RedisKeyConsts.GOME_GJ_ORDER_CREATE_REDIS_KEY,channelOrderId);
        String redisValue = redisManager.get(redisKey);
        if (!StringUtil.isNullOrEmpty(redisValue)) {
            return true;
        }

        return false;
    }

    /**
     * 缓存订单创建消息
     * @param channelOrderId
     * @param content
     */
    private void saveCreateOrderCacheData(String channelOrderId, String content)  {

        String redisKey = String.format(RedisKeyConsts.GOME_GJ_ORDER_CREATE_REDIS_KEY,channelOrderId);
        if (StringUtil.isNullOrEmpty(content)) {
            redisManager.del(redisKey);
            return;
        }

        if (redisManager.exists(redisKey)) {
            redisManager.set(redisKey, content);
        } else {
            redisManager.setex(redisKey,content,30 * 60 );
        }
    }

    /**
     * 测试代码
     * @param args
     */
    public static void main(String[] args) {

        GmgjRequestDTO gmgjRequestDTO = new GmgjRequestDTO();
        gmgjRequestDTO.setMethod("order");
        gmgjRequestDTO.setMsgId("49ca30982574471c8983588051aeff02");
        gmgjRequestDTO.setSign("654cce430d1031da2d20a1f7dd280093");
        gmgjRequestDTO.setBody("9B53870345BBC83DB1200C20583AA4DFBB49D7ACBB838F095412CC90550D4CBA594C5956BEF4E5C173C85039D7A7385C");

        // 验证签名
        if (!GmgjUtil.verfiyOrderRequestSign(gmgjRequestDTO)) {
            System.out.println("验证签名失败");
        }

        // 消息内容验证和解密
        if (StringUtil.isNullOrEmpty(gmgjRequestDTO.getBody())) {
            System.out.println("消息内容为空");
            return;
        }

        try {
            String orderMsg = AESUtil.decrypt(gmgjRequestDTO.getBody(), GmgjConsts.APP_SECRET);
            System.out.println("消息内容为: [" + orderMsg + "]" );
        } catch (Exception e) {
            System.out.println("解密消息失败");
        }
    }
}
